/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Application.Elements;
import Application.Network;

/**
 *
 * @author Stikmann
 */
public class CompositeElement extends Network{

    /**
     * Az azonositas megkonnyitesere, a modellnek nem resze
     * A controller allitja be
     */
    public String name="";

    /**
     * A kompozit elem tipusazonositasanak megkonnyitesere, a modellnek nem resze
     * A controller allitja be
     */
    public String typename="";

    @Override
    public String toString() {
        return (name==null?"":name+":")+(typename==null?"":typename+":")+
                getClass().getSimpleName()+"@"+Integer.toHexString(hashCode());
    }
    
    /**
     * Virtuális, vezeték-jellegű elem a ki- és bemenetek megoldásához. Azért belső
     * private osztály, mert nem akarok ebből kint konstruktort látni.
     */
    private class Pin extends Element{

        /**
         * Elvégzi a szimulációt, azaz a bemenetét a kimenetre rakja
         * @return Ha valtozott a kimenet, true, egyebkent false
         */
        public boolean simulate(){
            if(inputs.size()==1)
            {
                boolean newout=inputs.get(0).getOut();
                boolean result=newout!=out;
                out=newout;
                return result;
            }
            else
                return false;
        }

        /**
         * Leellenorzi az elemet. Minden inputra pontosan egy elem lehet kötve.
         * @return Ha nincs hiba, null, ha van, a hibauzenet.
         */
        @Override
        public String check(){
            if(inputs.size()!=1)
                return "A kompozit elem bemeneteire kívülről pontosan egy-egy elemet kell kapcsolni,"
                        + " kimeneteire belülről úgyszintén.";
            else
                return null;
        }
    }

    /**
     * Bemeneteknek virtuális elemek
     */
    private Pin inputs[];

    /**
     * Kimeneteknek virtuális elemek
     */
    private Pin outputs[];

    public CompositeElement(int inputszam, int outputszam){
       inputs = new Pin[inputszam];
       for (int i=0;i<inputszam;++i){
            inputs[i]=new Pin();
            addGate(inputs[i]);
       }

       outputs = new Pin[outputszam];
       for (int i=0;i<outputszam;++i){
            outputs[i]=new Pin();
            addGate(outputs[i]);
       }
    }

    /**
     * A kompoziton belül beköt egy inputot egy elemhez.
     * @param inputindex Az input száma amit kötünk
     * @param hova A belső elem, aminek a bemenetére az inputot kötjük
     */
    public void connectInput(int inputindex, Element hova){
        if (inputs.length>inputindex)
            hova.connectTo(inputs[inputindex]);
    }

    /**
     * A kompoziton belül kiköt egy elemet egy outputra
     * @param outputindex Az output száma amit kötünk
     * @param honnan A belső elem, aminek a kimenetét kikötjük
     */
    public void connectOutput(int outputindex, Element honnan){
        if (outputs.length>outputindex)
            outputs[outputindex].connectTo(honnan);
    }

    public boolean isOutput(Element mi){
        for(int i=0;i<outputs.length;++i)
            if (outputs[i]==mi)
                return true;
        return false;
    }
    
    /**
     * Input kapu referencia kérése bekötési célokra
     * @param index Az input száma, amit kérünk
     * @return Egy Element referencia, amit aztán lehet a connectGate()-ben használni
     * @see Network#connectGate(Application.Elements.Element, Application.Elements.Element)
     */
    public Element getInput(int index){
        if (index<inputs.length)
            return inputs[index];
        else
            return null;
    }

    /**
     * Outut kapu referencia kérése bekötési célokra
     * @param index Az outut száma, amit kérünk
     * @return Egy Element referencia, amit aztán lehet a connectGate()-ben használni
     * @see Network#connectGate(Application.Elements.Element, Application.Elements.Element)
     */
    public Element getOutput(int index){
        if (index<outputs.length)
            return outputs[index];
        else
            return null;
    }
}
